package lamma.lab.job;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.SortedMap;
import java.util.TreeMap;

import lamma.lab.job.ContextRunner.JobStep;
import lamma.lab2.job.LammaException;


/**
 * instead of a context, user can also run a single Job
 * 
 * simply execute steps one by one
 * 
 * @author maxcellent
 *
 */
@Deprecated
public class JobRunner {
	
	public static <T> T go(T job) {
		new JobRunner().run(job);
		return job;
	}
	
	/**
	 * 
	 * @param job
	 */
	public Result run(Object job) {
		try {
			this.start(job);
			return new Result(Result.Status.SUCCESS, null);
		} catch (InvocationTargetException e) {
			// exception thrown when the invoked method throws exception 
			return new Result(Result.Status.FAILED, e.getCause());
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return new Result(Result.Status.FAILED, 
					new LammaException("Please run health check", e));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			return new Result(Result.Status.FAILED, 
					new LammaException("Please run health check", e));
		} catch (Throwable e) {
			e.printStackTrace();
			return new Result(Result.Status.FAILED, e);
		}
	}

	private void start(Object job) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		SortedMap<Integer, JobStep> stepsMap = new TreeMap<Integer, JobStep>();

		// step1 : init job steps
		Method [] methods = job.getClass().getDeclaredMethods();
		for (Method method : methods) {
			Step step = method.getAnnotation(Step.class);
			
			if (step != null) {
				stepsMap.put(step.serial(), new JobStep(method.getName()));
			}
		}
		
		// step2 : execute steps		
		for (Integer serial : stepsMap.keySet()) {
			JobStep currJobStep = stepsMap.get(serial);
			job.getClass().getMethod(currJobStep.methodName).invoke(job);
		}
	}
}
